package org.sunrise.game.game.server;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.EventLoopGroup;
import lombok.Data;
import org.sunrise.game.center.client.ReportClient;
import org.sunrise.game.center.client.ReportClientManager;
import org.sunrise.game.center.message.ReportMessage;
import org.sunrise.game.center.server.NodeManager;
import org.sunrise.game.common.config.ConfigReader;
import org.sunrise.game.common.db.DbService;
import org.sunrise.game.common.log.LogCore;
import org.sunrise.game.common.network.client.BaseClient;
import org.sunrise.game.common.network.client.BaseClientManager;
import org.sunrise.game.game.human.HumanObjectManger;
import org.sunrise.game.game.message.GameMasterMessageManager;
import org.sunrise.game.game.message.GameReportMessageManager;
import org.sunrise.game.game.message.GameRpcMessageManager;
import org.sunrise.game.rpc.node.RpcNode;
import org.sunrise.game.rpc.node.RpcNodeManager;

import java.util.Map;
import java.util.Properties;
import java.util.concurrent.ConcurrentHashMap;

@Data
public class GameClient {
    private final int serverId;
    private final DbService dbService;

    private EventLoopGroup group = null;
    private Bootstrap b = null;
    private GameMasterMessageManager gameMasterMessageManager = null;
    private GameRpcMessageManager gameFromGlobalMessageManager = null;

    private Map<Integer, BaseClient> connectToExternals = new ConcurrentHashMap<>();
    private RpcNode rpcNode;

    public GameClient(int serverId) {
        this.serverId = serverId;
        this.dbService = new DbService();
        this.rpcNode = RpcNodeManager.createRpcNode(serverId);
        this.rpcNode.setFromOtherMessageManager(new GameRpcMessageManager(""));
        this.rpcNode.getFromOtherMessageManager().setRecvMsgQueue(HumanObjectManger.callBackQueue);
    }

    /**
     * 保证当前服务的唯一性
     */
    public void start() {
        rpcNode.start(dbService);
    }

    /**
     * 对外服断开连接，如果全部断开，则结束程序
     */
    public void externalOffline(int externalId) {
        BaseClient remove = connectToExternals.remove(externalId);
        if (remove != null) {
            BaseClientManager.remove(remove.getNodeId());
        }
        if (connectToExternals.isEmpty()) {
            System.exit(-1);
        }
    }

    public void connectExternal(ReportMessage message) {
        BaseClient baseClient = connectToExternals.get(message.getServerId());
        if (baseClient != null) {
            return;
        }
        var connectToExternal = new BaseClient(this.getClass().getSimpleName() + serverId + "-ConnectTo-External" + message.getServerId(), group, b) {
            @Override
            public void onStart() {
                super.onStart();
            }

            @Override
            public void onFail() {
                super.onFail();
                externalOffline(message.getServerId());
            }

            @Override
            public void onStop() {
                super.onStop();
                LogCore.ServerStartUp.info("Server Close, name = { GameServer }, serverId = {}, NodeId = {}", serverId, getNodeId());
            }
        };
        if (gameMasterMessageManager == null) {
            // 所有客户端共用一个消息管理器
            gameMasterMessageManager = new GameMasterMessageManager("");
        }
        connectToExternal.setClientHandler(r -> new GameToExternalHandler(serverId, connectToExternal.getNodeId()));
        connectToExternal.setMessageManager(gameMasterMessageManager);
        BaseClientManager.register(connectToExternal);

        connectToExternals.put(message.getServerId(), connectToExternal);
        connectToExternal.connect(message.getIp(), message.getPort());
    }

    public void connectMaster() {
        Properties properties = ConfigReader.getProp();
        if (properties == null) {
            return;
        }
        int id = Integer.parseInt(properties.getProperty("master.id"));
        String masterIp = properties.getProperty("master.address");
        int masterPort = Integer.parseInt(properties.getProperty("master.port"));

        var reportClient = ReportClientManager.createReportClient("GameClient" + serverId + "-ReportClient", NodeManager.NODE_TYPE_GAME, serverId, "", 0);
        reportClient.getConnectToCenter().setMessageManager(new GameReportMessageManager(reportClient.getConnectToCenter().getNodeId()));
        reportClient.connectMaster(masterIp, masterPort);
    }
}
